package cc.rengu.redp.hawk.service.impl;

import cc.rengu.redp.common.domain.QueryRequest;
import cc.rengu.redp.common.domain.RedpConstant;
import cc.rengu.redp.common.exception.RedisConnectException;
import cc.rengu.redp.common.exception.RedpException;
import cc.rengu.redp.common.redis.RedisService;
import cc.rengu.redp.common.utils.SortUtil;
import cc.rengu.redp.hawk.dao.HawkMonitorConfigMapper;
import cc.rengu.redp.hawk.domain.HawkIndex;
import cc.rengu.redp.hawk.domain.HawkMonitorConfig;
import cc.rengu.redp.hawk.domain.HawkMonitorConfigVo;
import cc.rengu.redp.hawk.domain.HawkMonitorShow;
import cc.rengu.redp.hawk.service.HawkMonitorConfigService;
import cc.rengu.redp.hawk.service.HawkMonitorService;
import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;

/**
 * @author xushitang
 */
@Slf4j
@Service
@Transactional
public class HawkMonitorConfigServiceImpl extends ServiceImpl<HawkMonitorConfigMapper, HawkMonitorConfig> implements HawkMonitorConfigService {

    @Autowired
    private HawkMonitorService hawkMonitorService;
    @Autowired
    private RedisService redisService;

    @Override
    public IPage<HawkMonitorConfigVo> findHawkMonitorConfig(QueryRequest request, HawkMonitorConfigVo hawkMonitorConfigVo) {
        LambdaQueryWrapper<HawkMonitorConfig> queryWrapper = new LambdaQueryWrapper<>();

        if (StringUtils.isNotBlank(hawkMonitorConfigVo.getHawkName())) {
            queryWrapper.eq(HawkMonitorConfig::getHawkName, hawkMonitorConfigVo.getHawkName());
        }

        Page<HawkMonitorConfig> page = new Page<>();
        SortUtil.handlePageSort(request, page, true);
        page = this.page(page, queryWrapper);

        Page<HawkMonitorConfigVo> pageVo = new Page<>();
        List<HawkMonitorConfigVo> hawkMonitorConfigVos = page.getRecords().stream()
                .map(c -> doToVo(c))
                .collect(Collectors.toList());
        pageVo.setCurrent(page.getCurrent())
                .setRecords(hawkMonitorConfigVos)
                .setSize(page.getSize())
                .setTotal(page.getTotal())
                .setPages(page.getPages());
        return pageVo;
    }

    @Override
    public void createHawkMonitorConfig(HawkMonitorConfigVo hawkMonitorConfigVo) {
        HawkMonitorConfig hawkMonitorConfig = voToDo(hawkMonitorConfigVo);
        if (this.save(hawkMonitorConfig)) {
            //构建主动采集定时器
            if (hawkMonitorConfigVo.getCollectionWay().equals(HawkMonitorConfig.COLLECTION_WAY_PULL)) {
                //采集模式，构建定时任务
                hawkMonitorConfigVo.setHawkId(hawkMonitorConfig.getHawkId());
                Long jobId = hawkMonitorService.createPullTask(hawkMonitorConfigVo);
                if (jobId != null) {
                    //保存定时任务ID
                    hawkMonitorConfig.setCollectionJobId(jobId);
                    this.updateById(hawkMonitorConfig);
                }
            }
        }
    }

    @Override
    public void deleteHawkMonitorConfig(String[] ids) throws RedpException {
        List<Long> longIds = Arrays.asList(ids).stream().map(Long::valueOf).collect(Collectors.toList());
        for (Long id : longIds) {
            HawkMonitorConfig hawkMonitorConfig = this.getById(id);
            try {
                //删除缓存
                redisService.del(RedpConstant.HAWK_CONFIG_PREFIX + id);
            } catch (RedisConnectException e) {
                log.error("delete hawkMonitorConfig from cache error.", e);
            }

            //删除主动采集定时器
            if (hawkMonitorConfig.getCollectionWay().equals(HawkMonitorConfig.COLLECTION_WAY_PULL)) {
                this.hawkMonitorService.deletePullTask(id);
            }
        }
        if (!this.removeByIds(longIds)) {
            throw new RedpException("没找到相应记录");
        }
    }

    @Override
    public void updateHawkMonitorConfig(HawkMonitorConfigVo hawkMonitorConfigVo) throws RedpException {
        if (!this.updateById(voToDo(hawkMonitorConfigVo))) {
            throw new RedpException("没找到相应记录");
        }

        try {
            //更新缓存
            if (StringUtils.isNotBlank(redisService.get(RedpConstant.HAWK_CONFIG_PREFIX + hawkMonitorConfigVo.getHawkId()))){
                redisService.set(
                        RedpConstant.HAWK_CONFIG_PREFIX + hawkMonitorConfigVo.getHawkId(),
                        JSON.toJSONString(hawkMonitorConfigVo));
            }
        } catch (RedisConnectException e) {
            log.error("update hawkMonitorConfig from cache error.", e);
        }

        //更新主动采集定时器
        if (hawkMonitorConfigVo.getCollectionWay().equals(HawkMonitorConfig.COLLECTION_WAY_PULL)) {
            this.hawkMonitorService.updatePullTask(hawkMonitorConfigVo);
        }
    }

    @Override
    public void useEnableHawkMonitorConfig(String id, Boolean useEnable) {
        boolean rs = this.update(new LambdaUpdateWrapper<HawkMonitorConfig>()
                .set(HawkMonitorConfig::getUseEnable, useEnable)
                .eq(HawkMonitorConfig::getHawkId, Long.valueOf(id)));
        if (rs) {
            HawkMonitorConfig hawkMonitorConfig = this.getById(id);
            try {
                //更新缓存
                if (StringUtils.isNotBlank(redisService.get(RedpConstant.HAWK_CONFIG_PREFIX + id))){
                    redisService.set(RedpConstant.HAWK_CONFIG_PREFIX + id, JSON.toJSONString(this.doToVo(hawkMonitorConfig)));
                }
            } catch (RedisConnectException e) {
                log.error("update hawkMonitorConfig from cache error.", e);
            }

            //更新主动采集定时器
            if (hawkMonitorConfig.getCollectionWay().equals(HawkMonitorConfig.COLLECTION_WAY_PULL)) {
                this.hawkMonitorService.switchPullTask(hawkMonitorConfig.getCollectionJobId(), useEnable);
            }
        }
    }

    @Override
    public HawkMonitorConfigVo getConfigById(String id) {
        String configJson = null;
        try {
            //优先从缓存获取
            configJson = redisService.get(RedpConstant.HAWK_CONFIG_PREFIX + id);
        } catch (RedisConnectException e) {
            log.error("get hawkMonitorConfig from cache error.", e);
        }
        if (StringUtils.isNotBlank(configJson)) {
            return JSON.parseObject(configJson, HawkMonitorConfigVo.class);
        }

        HawkMonitorConfig hawkMonitorConfig = this.getById(Long.valueOf(id));
        if (hawkMonitorConfig == null) {
            log.warn("get hawkMonitorConfig by id from db failed. hawkId:[{}]", id);
            return null;
        }

        HawkMonitorConfigVo hawkMonitorConfigVo = this.doToVo(hawkMonitorConfig);
        try {
            //缓存
            redisService.set(RedpConstant.HAWK_CONFIG_PREFIX + id, JSON.toJSONString(hawkMonitorConfigVo));
        } catch (RedisConnectException e) {
            log.error("cache hawkMonitorConfig error.", e);
        }
        return this.doToVo(hawkMonitorConfig);
    }

    @Override
    public List<HawkMonitorShow> getGraphToShow() {
        return this.baseMapper.selectList(new LambdaQueryWrapper<HawkMonitorConfig>()
                .eq(HawkMonitorConfig::getUseEnable, true)
                .eq(HawkMonitorConfig::getShowEnable, true)
                .orderByAsc(HawkMonitorConfig::getShowOrder)
        ).stream().map(i -> {
            HawkMonitorShow hawkMonitorShow = new HawkMonitorShow();
            hawkMonitorShow.setHawkId(i.getHawkId().toString());
            hawkMonitorShow.setShowChart(i.getShowChart());
            hawkMonitorShow.setHawkName(i.getHawkName());
            hawkMonitorShow.setShowOrder(i.getShowOrder());
            hawkMonitorShow.setShowGroupName(i.getShowGroupName());
            hawkMonitorShow.setShowChartParams(i.getShowChartParams());
            return hawkMonitorShow;
        }).collect(Collectors.toList());
    }

    @Override
    public List<String> groupList() {
        return this.baseMapper.selectObjs(new QueryWrapper<HawkMonitorConfig>().select("DISTINCT SHOW_GROUP_NAME"))
                .stream()
                .map(i -> (String)i)
                .sorted()
                .collect(Collectors.toList());
    }

    /**
     * do to vo
     * @param doo
     * @return
     */
    private HawkMonitorConfigVo doToVo(HawkMonitorConfig doo) {
        HawkMonitorConfigVo vo = new HawkMonitorConfigVo();
        vo.setHawkId(doo.getHawkId());
        vo.setCollectionFreq(doo.getCollectionFreq());
        vo.setCollectionUrl(doo.getCollectionUrl());
        vo.setCachePeriod(doo.getCachePeriod());
        vo.setHawkName(doo.getHawkName());
        vo.setCollectionWay(doo.getCollectionWay());
        vo.setIndexList(JSON.parseArray(doo.getIndexList(), HawkIndex.class));
        vo.setShowChart(doo.getShowChart());
        vo.setShowEnable(doo.getShowEnable());
        vo.setShowChartParams(doo.getShowChartParams());
        vo.setShowGroupName(doo.getShowGroupName());
        vo.setShowOrder(doo.getShowOrder());
        vo.setUseEnable(doo.getUseEnable());
        return vo;
    }

    /**
     * vo to do
     * @param vo
     * @return
     */
    private HawkMonitorConfig voToDo(HawkMonitorConfigVo vo) {
        HawkMonitorConfig doo = new HawkMonitorConfig();
        doo.setHawkId(vo.getHawkId());
        doo.setHawkName(vo.getHawkName());
        doo.setCollectionFreq(vo.getCollectionFreq());
        doo.setCollectionUrl(vo.getCollectionUrl());
        if (doo.getHawkId() == null) {
            //仅在新增数据确立采集方式，不可修改
            doo.setCollectionWay(vo.getCollectionWay());
        }
        doo.setCachePeriod(vo.getCachePeriod());
        doo.setIndexList(JSON.toJSONString(vo.getIndexList()));
        doo.setShowChart(vo.getShowChart());
        doo.setShowEnable(vo.getShowEnable());
        doo.setShowOrder(vo.getShowOrder());
        doo.setShowChartParams(vo.getShowChartParams());
        doo.setUseEnable(vo.getUseEnable());
        doo.setUseEnable(vo.getUseEnable());
        doo.setShowGroupName(vo.getShowGroupName());
        return doo;
    }
}
